package com.study.spmongodb.prize.task;

/**
 * @author study
 * @version 1.0
 * @date 2020/10/8 23:18
 */

import com.study.spmongodb.prize.config.RedisKeys;
import com.study.spmongodb.prize.entity.CardGame;
import com.study.spmongodb.prize.entity.CardGameProduct;
import com.study.spmongodb.prize.entity.CardProduct;
import com.study.spmongodb.prize.entity.CardProductDto;
import com.study.spmongodb.prize.task.entity.CardGameRules;
import com.study.spmongodb.prize.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 活动信息预热，每隔1分钟执行一次
 * 查找未来1分钟内（含），要开始的活动
 */
@Slf4j
@Component
public class GameTask {
    @Autowired
    private RedisUtil redisUtil;

    public void execute() {
        //当前时间
        Date now = new Date();
        //查询未来1分钟内要开始的活动|不查询数据库，模拟数据
        List<CardGame> list = new ArrayList<CardGame>();
        if (list.size() == 0) {
            //没有查找到开始的活动
            log.info("game list scan : size = 0");
            return;
        }
        log.info("game list scan : size = {}", list.size());
        //有相关活动数据，则将活动数据预热，进redis
        list.forEach(game -> {
            //活动开始时间
            final long start = game.getStarttime().getTime();
            final long end = game.getEndtime().getTime();

            //计算活动结束时间到现在还有多少秒，作为redis key过期时间
            long expire = (end - now.getTime()) / 1000;
            //活动持续时间
            long duration = end - start;
            //活动基本信息 存储到redis 设置永不过期
            game.setStatus(1);
            redisUtil.set(RedisKeys.INFO + game.getId(), game, -1);

            // 活动奖品信息
            List<CardProductDto> products = getByGameId(game.getId());
            Map<Integer, CardProduct> productMap = new HashMap<>(products.size());
            products.forEach(p -> productMap.put(p.getId(), p));
            log.info("load product type:{}", productMap.size());

            //奖品数量等配置信息
            List<CardGameProduct> gameProducts = gCardGameProduct(game.getId());
            log.info("load bind product:{}", gameProducts.size());

            //令牌桶
            List<Long> tokenList = new ArrayList<>();
            gameProducts.forEach(cgp -> {
                //生成 amout个 start到end之间的随时间戳作为令牌
                for (int i = 0; i < cgp.getAmount(); i++) {
                    long rnd = start + new Random().nextInt((int) duration);
                    //为什么乘1000，再额外加一个随机数呢？ - 防止时间段奖品多时重复
                    //记得取令牌判断时间时，除以1000，还原真正的时间戳
                    long token = rnd * 1000 + new Random().nextInt(999);
                    //将令牌放入令牌桶
                    tokenList.add(token);
                    //以令牌作为key，对应商品为value，创建缓存
                    log.info("token -> game : {} -> {}", token / 1000, productMap.get(cgp.getProductid()).getName());
                    //token到实际奖品之间建立映射关系
                    redisUtil.set(RedisKeys.TOKEN + game.getId() + "_" + token, productMap.get(cgp.getProductid()), expire);
                }
            });
            //排序后放入redis队列
            Collections.sort(tokenList);
            log.info("load tokens:{}", tokenList);

            //从右侧压入队列，从左到右，时间戳逐个增大
            redisUtil.rightPushAll(RedisKeys.TOKENS + game.getId(), tokenList);
            redisUtil.expire(RedisKeys.TOKENS + game.getId(), expire);

            //奖品策略配置信息
            List<CardGameRules> rules = null;
            //遍历策略，存入redis
            rules.forEach(r -> {
                redisUtil.hset(RedisKeys.MAXGOAL + game.getId(), r.getUserlevel() + "", r.getGoalTimes());
                redisUtil.hset(RedisKeys.MAXENTER + game.getId(), r.getUserlevel() + "", r.getEnterTimes());
                log.info("load rules:level={},enter={},goal={}", r.getUserlevel(), r.getEnterTimes(), r.getGoalTimes());
            });
            redisUtil.expire(RedisKeys.MAXGOAL + game.getId(), expire);
            redisUtil.expire(RedisKeys.MAXENTER + game.getId(), expire);

            //活动状态变更为已预热，禁止管理后台再随便变动
            game.setStatus(1);
            //保存到数据库

        });

    }

    /**
     * 获取 活动 奖品 数量
     *
     * @param id
     * @return
     */
    private List<CardGameProduct> gCardGameProduct(Integer id) {
        return null;
    }

    /**
     * 根据活动查询 奖品
     *
     * @param id 活动ID
     * @return
     */
    private List<CardProductDto> getByGameId(Integer id) {
        return null;
    }
}
